/**
 *Copyright (c) 2024 watereyes
 * safetymanagement is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */
package com.koron.purpose.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.koron.audit.approval.AfterApprovalService;
import com.koron.audit.domain.Audit;
import com.koron.audit.management.FlowManagement;
import com.koron.common.bean.StaffBean;
import com.koron.common.dfs.FastDFSClientWrapper;
import com.koron.common.domain.DataBean;
import com.koron.common.generator.DefaultIdGenerator;
import com.koron.purpose.bean.ContributoryRealityDetailBean;
import com.koron.purpose.mapper.UsingStandBookMapper;
import com.koron.purpose.service.api.UsingStandBookService;
import com.koron.purpose.utils.BusinessCode;
import com.koron.purpose.utils.PdfFileUtil;
import org.apache.commons.lang3.StringUtils;
import org.koron.ebs.mybatis.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.swan.bean.MessageBean;

import java.math.BigDecimal;
import java.util.*;

@SuppressWarnings("deprecation")
@Service
public class UsingStandBookServiceImpl implements UsingStandBookService, AfterApprovalService, InitializingBean {
    private final Logger logger = LoggerFactory.getLogger(UsingStandBookServiceImpl.class);
    // 状态标记(0-审批中 1-审批通过 2-草稿)
    private final String STATUS_FLAG_0 = "0";
    // 状态标记(0-审批中 1-审批通过 2-草稿)
    private final String STATUS_FLAG_1 = "1";
    // 状态标记(0-审批中 1-审批通过 2-草稿)
    private final String STATUS_FLAG_2 = "2";

    @Value("${UsingSB_template_key}")
    private String templateKey;

    @Autowired
    private FlowManagement flowManagement;

    @Autowired
    private FastDFSClientWrapper fastDFSClientWrapper;

    @Autowired
    private PdfFileUtil pdfFileUtil;

    @Override
    public MessageBean<DataBean<Map>> queryForList(String corpCode, Integer year, String manager, Integer page, Integer pageSize,String keyword) {
        MessageBean<DataBean<Map>> msg = new MessageBean<>();
        try (SessionFactory factory = new SessionFactory()) {
            UsingStandBookMapper mapper = factory.getMapper(UsingStandBookMapper.class);
            // 查询
            Map map = new HashMap();
            map.put("corpCode", corpCode);
            map.put("year", year);
            map.put("manager", manager);
            page = (page == null || page < 1) ? 1 : page;
            pageSize = (pageSize == null || pageSize < 1) ? 10 : pageSize;
            int pageStart = (page - 1) * pageSize;
            map.put("pageStart", pageStart);
            map.put("pageStop", pageSize);
            map.put("status_flag_1", STATUS_FLAG_1);
            map.put("keyword",keyword);
            List<Map> list = mapper.queryForList(map);
            DataBean<Map> dataBean = new DataBean<>();
            dataBean.setList(list);
            dataBean.setPageSize(pageSize);
            dataBean.setPageNo(page);
            // 总条数
            Integer totalNumber = mapper.countQueryForList(map);
            int num = totalNumber / pageSize;
            // 总页数
            Integer totalPage = totalNumber % pageSize == 0 ? num : num + 1;
            dataBean.setTotalNumber(totalNumber);
            dataBean.setTotalPage(totalPage);
            msg.setData(dataBean);
            msg.setCode(BusinessCode.SUCCESS.getCode());
            msg.setDescription(BusinessCode.SUCCESS.getDescription());
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            msg.setCode(BusinessCode.EXCEPTION.getCode());
            msg.setDescription(BusinessCode.EXCEPTION.getDescription());
        }
        return msg;
    }

    @Override
    public MessageBean<Map> queryById(String id) {
        MessageBean msg = MessageBean.create(BusinessCode.SUCCESS.getCode(), BusinessCode.SUCCESS.getDescription(), void.class);
        if (StringUtils.isEmpty(id)) {
            msg.setCode(BusinessCode.INSUFFICIENT_PARAM.getCode());
            msg.setDescription(BusinessCode.INSUFFICIENT_PARAM.getDescription());
            return msg;
        }
        try (SessionFactory factory = new SessionFactory()) {
            UsingStandBookMapper mapper = factory.getMapper(UsingStandBookMapper.class);
            // 查询
            Map bean = mapper.queryById(id);
            if (bean == null) {
                msg.setCode(BusinessCode.EXCEPTION.getCode());
                msg.setDescription("未查到该使用台账");
            } else {
                List<Map> list = mapper.getDetailById(id);
                if (list != null && list.size() > 0) {
                    for (Map map : list) {
                        // 根据 投入计划明细id 查询实际投入明细
                        map.put("realityDetails", mapper.getRealityDetailById(map.get("id").toString()));
                    }
                }
                bean.put("details", list);
                msg.setData(bean);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            msg.setCode(BusinessCode.EXCEPTION.getCode());
            msg.setDescription(BusinessCode.EXCEPTION.getDescription());
        }
        return msg;
    }

    @Override
    public List<Map> exportQueryForList(String corpCode, Integer year, String manager) {
        List<Map> list = null;
        try (SessionFactory factory = new SessionFactory()) {
            UsingStandBookMapper mapper = factory.getMapper(UsingStandBookMapper.class);
            Map map = new HashMap();
            map.put("corpCode", corpCode);
            map.put("year", year);
            map.put("manager", manager);
            // 查询 状态标记(0-审批中 1-审批通过 2-草稿) 为审批通过的数据
            map.put("status_flag_1", STATUS_FLAG_1);
            // 查询
            list = mapper.queryExportForList(map);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
        }
        return list;
    }

    @Override
    public MessageBean save(StaffBean user, String planId, String status, ContributoryRealityDetailBean realityDetailBean, String personCode) {
        MessageBean msg = MessageBean.create(BusinessCode.SUCCESS.getCode(), BusinessCode.SUCCESS.getDescription(), void.class);
        SessionFactory factory = new SessionFactory();
        // 参数校验
        List<Date> times = realityDetailBean.getTime();
        if (times != null && times.size() > 0) {
            for (Date time : times) {
                if (time == null) {
                    factory.close();
                    msg.setCode(BusinessCode.INSUFFICIENT_PARAM.getCode());
                    msg.setDescription("实际投入时间不能为空");
                    return msg;
                }
            }
        }
        List<BigDecimal> realityMoneys = realityDetailBean.getRealityMoney();
        if (realityMoneys != null && realityMoneys.size() > 0) {
            for (BigDecimal realityMoney : realityMoneys) {
                if (realityMoney == null) {
                    factory.close();
                    msg.setCode(BusinessCode.INSUFFICIENT_PARAM.getCode());
                    msg.setDescription("实际金额不能为空");
                    return msg;
                }
            }
        }
        List<String> personCharges = realityDetailBean.getPersonCharge();
        if (personCharges != null && personCharges.size() > 0) {
            for (String personCharge : personCharges) {
                if (StringUtils.isEmpty(personCharge)) {
                    factory.close();
                    msg.setCode(BusinessCode.INSUFFICIENT_PARAM.getCode());
                    msg.setDescription("责任人不能为空");
                    return msg;
                }
            }
        }
        List<String> personChargeNames = realityDetailBean.getPersonChargeName();
        if (personChargeNames != null && personChargeNames.size() > 0) {
            for (String personChargeName : personChargeNames) {
                if (StringUtils.isEmpty(personChargeName)) {
                    factory.close();
                    msg.setCode(BusinessCode.INSUFFICIENT_PARAM.getCode());
                    msg.setDescription("责任人不能为空");
                    return msg;
                }
            }
        }
        try {
            UsingStandBookMapper mapper = factory.getMapper(UsingStandBookMapper.class);
            BigDecimal realityMoney = new BigDecimal(0);
            if (realityDetailBean != null && realityDetailBean.getRealityMoney() != null && realityDetailBean.getRealityMoney().size() > 0) {
                List<BigDecimal> moneys = realityDetailBean.getRealityMoney();
                for (BigDecimal money : moneys) {
                    realityMoney = realityMoney.add(money);
                }
            }
            // 设定最大金额
            BigDecimal maxMoney = new BigDecimal(999999999.99);
            if (realityMoney.compareTo(maxMoney) > 0) {
                factory.close(false);
                msg.setCode(BusinessCode.EXCEPTION.getCode());
                msg.setDescription("金额过大!");
                return msg;
            }
            // 查询
            Map bean = mapper.queryById(planId);
            if (bean == null) {
                factory.close(false);
                msg.setCode(BusinessCode.FAILURE.getCode());
                msg.setDescription("该记录已失效，请刷新页面!");
                return msg;
            }
            String flag = Optional.ofNullable(bean.get("detailStatusFlag")).orElse("").toString();
            flag = "".equals(flag) ? "0" : flag;
            if (!"0".equals(flag)) {
                factory.close(false);
                msg.setCode(BusinessCode.FAILURE.getCode());
                msg.setDescription("只能修改未提交的使用台账记录!");
                return msg;
            }
            // 根据 投入计划id 修改投入计划的 实际投入金额
            updatePlanRealMoneyById(planId, realityDetailBean, status, mapper);
            // 保存 投入实际明细
            saveRealityDetail(planId, realityDetailBean, status, mapper);
            // 如果为保存，则进入流程
            if ("1".equals(status)) {
                if (StringUtils.isEmpty(personCode)) {
                    factory.close(false);
                    msg.setCode(BusinessCode.EXCEPTION.getCode());
                    msg.setDescription("审批人不能为空!");
                    return msg;
                }
                Audit audit = new Audit("使用台账", "使用台账审批", user.getName(), new Date());
                audit.setTitle("使用台账");
                audit.setDescription("使用台账审批");
                audit.setCorpCode(Optional.ofNullable(bean.get("corpCode")).orElse("").toString());
                audit.setCorpName(Optional.ofNullable(bean.get("corpName")).orElse("").toString());

                audit.setId(DefaultIdGenerator.getInstance().generateLongId());
                audit.setInitiatorCode(user.getCode());
                audit.setTarget(this.getClass().getName());
                audit.setTemplateKey(templateKey);
                audit.setOperation(1);
                audit.setState(1);
                audit.setFlowType(1);
                audit.setFlowName("使用台账审批");
                audit.setSetCode("target_duty");
                audit.setInitiatorAccount(user.getUserid());
                List<String> idList = Arrays.asList(planId);
                audit.setBusinessIds(new Gson().toJson(idList));
                Map map = new HashMap();
                map.put("personCode", personCode);
                if (!flowManagement.initFlow(user, audit, map)) {
                    factory.close(false);
                    msg.setCode(com.koron.hazardsource.util.BusinessCode.MESSAGE_CODE_FLOW_EXCEPTION);
                    msg.setDescription(com.koron.hazardsource.util.BusinessCode.MESSAGE_DESCRIPTION_FLOW_EXCEPTION);
                    return msg;
                }
            }
            factory.close();
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            factory.close(false);
            msg.setCode(BusinessCode.EXCEPTION.getCode());
            msg.setDescription(BusinessCode.EXCEPTION.getDescription());
        }
        return msg;
    }

    /**
     * 根据 投入计划id 修改投入计划的 实际投入金额
     *
     * @param id             投入计划id
     * @param realityDetails 实际投入明细
     * @param status         状态标记(0-草稿 1-保存)
     * @param mapper
     * @throws Exception
     */
    private void updatePlanRealMoneyById(String id, ContributoryRealityDetailBean realityDetails, String status, UsingStandBookMapper mapper) throws Exception {
        BigDecimal realityMoney = new BigDecimal(0);
        if (realityDetails != null && realityDetails.getRealityMoney() != null && realityDetails.getRealityMoney().size() > 0) {
            List<BigDecimal> moneys = realityDetails.getRealityMoney();
            for (BigDecimal money : moneys) {
                realityMoney = realityMoney.add(money);
            }
        }
        // 使用台账状态(0-未提交 1-审批中 2-审批通过)
        String detailStatusFlag = null;
        if ("1".equals(status)) {
            detailStatusFlag = "1";
        }
        int i = mapper.updatePlanRealMoneyById(id, realityMoney, detailStatusFlag);
        if (i != 1) {
            throw new Exception("修改投入计划实际投入金额失败!");
        }
    }

    /**
     * 保存 投入实际明细
     *
     * @param contributoryPlanId 投入计划id
     * @param realityDetailBean  投入实际明细
     * @param statusFlag         状态标记(0-草稿 1-保存)
     * @param mapper
     */
    private void saveRealityDetail(String contributoryPlanId, ContributoryRealityDetailBean realityDetailBean, String statusFlag, UsingStandBookMapper mapper) throws Exception {
        // 根据 投入计划id 查询所有 投入实际明细
        List<Map> allRealDetails = mapper.queryAllRealDetails(contributoryPlanId);
        // 删除 投入计划下的 所有为草稿状态的 投入实际明细
        int i = mapper.deleteRealDetails(contributoryPlanId);
        if (i != allRealDetails.size()) {
            throw new Exception("删除投入明细失败!");
        }
        JSONObject jsonObject;
        // 获取所有草稿状态的历史附件FileUrl list
        List<JSONObject> old_files = new LinkedList<>();
        String str;
        if (allRealDetails != null && allRealDetails.size() > 0) {
            for (Map map : allRealDetails) {
                if (!Objects.isNull(map.get("accessorys"))
                        && (str = map.get("accessorys").toString()).length() > 0
                        && "0".equals(map.get("statusFlag").toString())) {
                    jsonObject = JSON.parseObject(str);
                    Optional.ofNullable(jsonObject).ifPresent(jsonObject1 -> {
                        old_files.add(jsonObject1);
                    });
                }
            }
        }
        // 所有新增附件FileUrl list
        List<String> fileUrls = new LinkedList<>();
        // 新增 投入实际明细
        if (realityDetailBean != null) {
            List<Map> realDetailList = new LinkedList<>();
            Map map;
            MultipartFile file;
            String fileUrl;
            String pdfUrl;
            List<String> contributoryPlanIds = realityDetailBean.getContributoryPlanId();
            int num;
            if (contributoryPlanIds != null && (num = contributoryPlanIds.size()) > 0) {
                List<String> ids = realityDetailBean.getId();
                List<String> detailIds = realityDetailBean.getDetailId();
                List<String> contributoryDetails = realityDetailBean.getContributoryDetail();
                List<Date> times = realityDetailBean.getTime();
                List<BigDecimal> realityMoneys = realityDetailBean.getRealityMoney();
                List<String> effectAppraisals = realityDetailBean.getEffectAppraisal();
                List<String> personCharges = realityDetailBean.getPersonCharge();
                List<String> personChargeNames = realityDetailBean.getPersonChargeName();
                List<String> remarks = realityDetailBean.getRemark();
                List<MultipartFile> files = realityDetailBean.getFile();
                int fileSize = 0;
                if (files != null) {
                    fileSize = files.size();
                }
                List<String> accessorys = realityDetailBean.getAccessorys();
                for (int j = 0; j < num; j++) {
                    // 检查 当前 bean 是否是 状态标记(0-草稿 1-保存)为保存 的数据，如果是，continue，保存状态不允许修改删除
                    if (isStatusSubmit(ids.get(j), allRealDetails)) {
                        continue;
                    }
                    map = new HashMap();
                    map.put("id", DefaultIdGenerator.getInstance().generateLongId());
                    map.put("contributoryPlanId", contributoryPlanId);
                    map.put("detailId", detailIds.get(j));
                    map.put("contributoryDetail", contributoryDetails.get(j));
                    map.put("time", times.get(j));
                    map.put("realityMoney", realityMoneys.get(j));
                    map.put("effectAppraisal", effectAppraisals.get(j));
                    map.put("personCharge", personCharges.get(j));
                    map.put("personChargeName", personChargeNames.get(j));
                    map.put("remark", remarks.get(j));
                    if (j < fileSize && files.get(j) != null) {
                        file = files.get(j);
                        jsonObject = new JSONObject();
                        jsonObject.put("filename", file.getOriginalFilename());
                        fileUrl = fastDFSClientWrapper.uploadFile(file);
                        jsonObject.put("fileUrl", fileUrl);
                        fileUrls.add(fileUrl);
                        try {
                            pdfUrl = pdfFileUtil.getPdfUrl(file, fastDFSClientWrapper);
                            jsonObject.put("pdfUrl", pdfUrl);
                        } catch (Exception e) {
                            logger.error(e.getMessage(),e);
                        }
                        map.put("accessorys", jsonObject.toJSONString());
                    } else {
                        if (accessorys != null && j < accessorys.size() && !StringUtils.isEmpty(accessorys.get(j))) {
                            jsonObject = JSON.parseObject(accessorys.get(j));
                            fileUrl = jsonObject.get("fileUrl") == null ? "" : jsonObject.get("fileUrl").toString();
                            fileUrls.add(fileUrl);
                            map.put("accessorys", accessorys.get(j));
                        }
                    }
                    map.put("statusFlag", statusFlag);
                    realDetailList.add(map);
                }
                if (realDetailList != null && realDetailList.size() > 0) {
                    mapper.insertRealDetails(realDetailList);
                }
            }
        }
        if (old_files.size() > 0) {
            for (JSONObject url : old_files) {
                if (fileUrls.stream().anyMatch(fileUrl -> fileUrl.equals(url.getString("fileUrl")))) {// 不存在就删除
                    Optional.ofNullable(url.get("fileUrl")).ifPresent(u -> {
                        if (!StringUtils.isEmpty(u.toString())) {
                            fastDFSClientWrapper.deleteFile(u.toString());
                        }
                    });
                    Optional.ofNullable(url.get("pdfUrl")).ifPresent(u -> {
                        if (!StringUtils.isEmpty(u.toString())) {
                            fastDFSClientWrapper.deleteFile(u.toString());
                        }
                    });
                }
            }
        }
    }

    /**
     * 判断url 是否在list中存在
     *
     * @param url
     * @param list
     * @return
     */
    private boolean filter(String url, List<String> list) {
        if (list == null || list.size() == 0) {
            return false;
        }
        for (String str : list) {
            if (url.equals(str)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检查 当前 bean 是否是 状态标记(0-草稿 1-保存)为保存 的数据，如果是,返回true
     *
     * @param id             投入实际明细id
     * @param allRealDetails 投入实际明细list
     * @return
     */
    private boolean isStatusSubmit(String id, List<Map> allRealDetails) {
        if (StringUtils.isEmpty(id)) {
            return false;
        }
        if (allRealDetails == null || allRealDetails.size() == 0) {
            return false;
        }
        for (Map map : allRealDetails) {
            if (id.equals(map.get("id").toString()) && "1".equals(map.get("statusFlag").toString())) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void editApproval(Audit audit) {
        Optional.ofNullable(audit)
                .map(obj -> obj.getBusinessIds())
                .map(ids -> {
                    List<String> list = JSON.parseArray(ids, String.class);
                    return Optional.ofNullable(list);
                }).map(idsList -> {
            List<String> idList = idsList.get();
            Optional.ofNullable(idList).map(ids -> {
                SessionFactory factory = new SessionFactory();
                try {
                    UsingStandBookMapper mapper = factory.getMapper(UsingStandBookMapper.class);
                    for (String id : ids) {
                        // 根据 投入计划id修改  使用台账状态(0-未提交 1-审批中 2-审批通过)
                        if (mapper.updateContPlanDStatusById(id, "2") != 1) {
                            factory.close(false);
                            return null;
                        }
                    }
                    factory.close();
                } catch (Exception e) {
                    logger.error(e.getMessage(),e);
                    factory.close(false);
                }
                return null;
            });
            return null;
        });
    }

    @Override
    public void discardApproval(Audit audit) {

    }

    @Override
    public void processDiscard(Audit audit) {
        Optional.ofNullable(audit)
                .map(obj -> obj.getBusinessIds())
                .map(ids -> {
                    List<String> list = JSON.parseArray(ids, String.class);
                    return Optional.ofNullable(list);
                }).map(idsList -> {
            List<String> idList = idsList.get();
            Optional.ofNullable(idList).map(ids -> {
                SessionFactory factory = new SessionFactory();
                try {
                    UsingStandBookMapper mapper = factory.getMapper(UsingStandBookMapper.class);
                    for (String id : ids) {
                        // 根据 投入计划id修改  使用台账状态(0-未提交 1-审批中 2-审批通过)
                        if (mapper.updateContPlanDStatusById(id, "0") != 1) {
                            factory.close(false);
                            return null;
                        }
                        mapper.updateContributoryRealityDetailByPlanId(id, "0");
                    }
                    factory.close();
                } catch (Exception e) {
                    logger.error(e.getMessage(),e);
                    factory.close(false);
                }
                return null;
            });
            return null;
        });
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        flowManagement.getHandlers().put(this.getClass().getName(), new UsingStandBookServiceImpl());
    }

    @Override
    public void reject(Audit audit, List<String> userIdList) {
        // TODO 流程驳回操作
    }

    @Override
    public void passApproval(Integer operation, Audit audit) {
        // TODO 流程提交成功操作
    }
}
